//////////////////////////////////////////
//  File       	: adx.cpp               //
//  Written by	: ludmiloff@gmail.com	//
//  Copyright  	: GPL                   //
//////////////////////////////////////////

#include "adx.h"
#include "wmutils.h"
#include "dbusadaptor.h"
#include "sysmenu.h"

#define WM_DBUS_SERVICE "org.freedesktop.AnticoDeluxe"

#define HAL_DOMAIN "org.freedesktop.Hal"
#define HAL_PATH "/org/freedesktop/Hal/devices/computer"
#define HAL_SERVICE "org.freedesktop.Hal.Device.SystemPowerManagement"

#define BASE_EVENT_MASK \
    SubstructureNotifyMask |\
    StructureNotifyMask |\
    SubstructureRedirectMask |\
    ButtonPressMask |\
    ButtonReleaseMask |\
    FocusChangeMask |\
    PropertyChangeMask |\
    ColormapNotify

#ifdef HAVE_COMPOSITOR
#define MAIN_EVENT_MASK BASE_EVENT_MASK | ExposureMask
#else
#define MAIN_EVENT_MASK BASE_EVENT_MASK
#endif

Adx *deluxe;
QApplication::EventFilter prev_x11_event_filter = 0;

extern Panel *toppanel;
extern Desktop *adesktop;
extern Dockbar *dock;

Adx::Adx(int &argc, char **argv) : QApplication(argc, argv),
    WMCtrl(0),
    hal(0), stg(0), alttab(0), client(0)
{	
    m_Process = process_Initializing;
    deluxe = this;

	setOrganizationName("AnticoDeluxe");
	setApplicationName("AnticoDeluxe");
	readAdxSettings();

    dpy = display();
    XSetErrorHandler(handleXError);

	Utils::createNetWMAtoms(dpy);

    //TODO: check for various extensions

    createTimeStampWindow();
    createScreens();
    xGrabCount = 0;
	
    //iconTheme = new AmeIconTheme("/usr/share/icons/");
    //iconTheme->setTheme("Faenza");
    //iconTheme->loadIcon("gedit", AmeIconThemeDir::Application, 90);
	
    prev_x11_event_filter = qApp->setEventFilter(this->x11_event_filter);

	m_Process = process_Normal;
    QTimer::singleShot(0, this, SLOT(wmInit()));
}	

Adx::~Adx()
{
	qDebug() << "TERMINATED, NORMAL EXIT";
	delete adesktop;
	delete toppanel;
	delete dock;
}

void Adx::wmInit()
{
    dock = new Dockbar();
    toppanel = new Panel();

    adesktop = new Desktop();
    adesktop->init(TOP_PANEL_HEIGHT);

    adesktop->show();
    dock->show();
    toppanel->currentApp->setCurrent("Desktop", 0);
    toppanel->show();

    // DBus interfaces
    WMCtrl = new DBusAdaptor(&obj);
    QDBusConnection::sessionBus().registerObject("/", &obj);
    if (!QDBusConnection::sessionBus().registerService(WM_DBUS_SERVICE)) {
        qDebug() << "UNABLE TO REGISTER DBUS SERVICE";
        exit(1);
    }

    QDBusConnection bus = QDBusConnection::systemBus();
    hal = new QDBusInterface(HAL_DOMAIN, HAL_PATH, HAL_SERVICE, bus);

    alttab = NULL;
    keygrab = false;
    ctrlgrab = false;

    toppanel->sysBtn->rebuildMenu(dock->autoHide);
    QTimer::singleShot(250, this, SLOT(manageRunningClients()));
}

void Adx::createTimeStampWindow()
{
    XSetWindowAttributes attr;
    attr.event_mask = PropertyChangeMask;
    attr.override_redirect = TRUE;
    timeStampWin =
        XCreateWindow(dpy, DefaultRootWindow(dpy), -100, -100, 10, 10, 0,0,
                      CopyFromParent, CopyFromParent,
                      CWEventMask | CWOverrideRedirect, &attr);
}

void Adx::createScreens()
{
    nscreens = QApplication::desktop()->screenCount();
    qDebug() << "number of screens " << nscreens;

    for (int i = 0; i < nscreens; i++) {
		MyScreen *screen = new MyScreen(i, MAIN_EVENT_MASK, false);
		if (screen->initialized) {
		   screens.append(screen);
		   XSetInputFocus(dpy, screen->wmwindow->winId(), RevertToPointerRoot, CurrentTime);
		}
    }

}


MyScreen *Adx::getScreenFromRoot(Window root)
{
    for (int i = 0; i < nscreens; i++) {
        MyScreen *screen = screens.at(i);
        if (screen->xroot == root)
            return screen;
    }
    return NULL;
}

Client *Adx::getClientFromWindow(Window w)
{
    return clients.value(w);
}


// Window management routines
void Adx::minimizeOthers(Client *thisClient)
{
	m_Process = process_MinimizingWindows;
    foreach (client, clients)
	{
		// TODO: check frame/window type. Do not iconify 
		// some types like splash screen etc.
		if (client->clientState == NormalState && client->winId() != thisClient->winId())
			client->iconifyFast();
	}
	thisClient->setChildFocus(0, CurrentTime);
	m_Process = process_Normal;
}

void Adx::minimizeAll()
{
	m_Process = process_MinimizingWindows;
    foreach(client, clients) {
		// TODO: check frame/window type. Do not iconify
		// some types like splash screen etc.
		if (client->clientState == NormalState)
			client->iconifyFast();
	}
	toppanel->currentApp->setCurrent("Desktop", NULL);
	XUngrabKeyboard(display(), CurrentTime);
	XGrabKeyboard(display(), rootWindow(), TRUE, GrabModeAsync, GrabModeAsync, CurrentTime);
	
	m_Process = process_Normal;
}

void Adx::showAll()
{
	dock->removeAll();
}

void Adx::onDockIconRemoved(Client *client)
{
	toppanel->iconIsRemoved(client);
	XRaiseWindow(display(), client->winId());
	restack(client);
	toppanel->currentApp->setCurrent(client->appName, client);
	client->setChildFocus(0, CurrentTime);
}

void Adx::manageRunningClients()
{
	qDebug() << "Get already running clients ...";
	Window c_win, w1, w2, *wins;
	uint nwins, cwin;
	XWindowAttributes attr;
	if (XQueryTree(display(), rootWindow(), &w1, &w2, &wins, &nwins) == 0 || ! nwins) {
		qDebug() << "No already running clients ...";
		return;
	}
	
	for (cwin=0; cwin < nwins; cwin++) {
		c_win = wins[cwin];
		//qDebug() << "run process:" << cwin << "name:" << c_win;
		if (isSystemWidget(c_win))
			continue;
		XGetWindowAttributes(display(), c_win, &attr);
		
        if ((client = clients.value(c_win)) != NULL) {
			//qDebug() << "map process:" << cwin << "name:" << c_win;
			client->map();
		}
		
		else if (attr.map_state == IsViewable && ! attr.override_redirect) {
			//qDebug() << "create process:" << cwin << "name:" << c_win;
			createMyWindow(c_win);
		}
	}
}

void Adx::unmanageRunningClients()
{
}

void Adx::focusTopmostClient()
{
	Window c_win, w1, w2, *wins;
	uint nwins;
	if (XQueryTree(display(), rootWindow(), &w1, &w2, &wins, &nwins) == 0 || ! nwins) {
		//qDebug() << "No running clients ...";
		return;
	}
	
	for (int cwin=nwins-1; cwin >= 0; cwin--) {
		c_win = wins[cwin];
		//qDebug() << "run process:" << cwin << "name:" << c_win;
		
        if ((client = decors.value(c_win)) != NULL ||
            (client = clients.value(c_win)) != NULL) {
			if (client->clientState == NormalState) {
				toppanel->currentApp->setCurrent(client->appName, client);
				client->setDecorState(true);
				XRaiseWindow(display(), client->clientId);
				restack(client);				
				client->setChildFocus(0, CurrentTime);
				break;
			}
		}
	}
}


void Adx::setHighlightColor(const QColor &col)
{
	QPalette pal = QApplication::palette();
	pal.setColor(QPalette::Highlight, col);
	QApplication::setPalette(pal);
}

void Adx::setMinimizeOnDblClick(bool active)
{
	minimizeDblClick = active;
    foreach(client, clients) {
		client->setDblMinimizeClick(active);
	}

}

void Adx::wmCleanup()
{
    foreach(client, clients) {
		qDebug() << "Quit process:" << client->clientId;
		XRemoveFromSaveSet(display(), client->clientId);
		XReparentWindow(display(), client->clientId, rootWindow(), client->n_px, client->n_py);
		client->destroyClient();
	}

    clients.clear();
    decors.clear();

	dock->close();
	toppanel->close();
	XSync(display(), FALSE);
	flush();
}


